package websocket

import (
	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
	"log"
	"net/http"
	"spirit/utils"
)

/*
1.断网后，client一定时间内写都能成功返回，但是因为断网实际没有发送出去，数据写到了底层tcp的缓冲区。
2.过一段时间后，1分钟左右，client Read返回错误“read: operation timed out”。Write会返回“write: broken pipe”。这个可能是Go中websocket实现时加了超时机制，也有可能是设置了底层TCP SO_KEEPALIVE，检测到了网络不可用。
3.在Read/Write返回错误之前，重新连上网络，可以继续发送和接受数据。这个可以从TCP的实现上解释。TCP连接并不是物理连接，本质上就是连接两端各自系统内核维护的一个四元组。客户端断线，在一定时间内并不会导致四元组的释放。所以当连上网线后此TCP连接可以自动恢复，继续进行正常的网络操作。
4.断线重连到其他网络，相当于断网。这个很好解释，连上其他网络，IP地址都改变了，之前的四元组不可用。
*/
var WsMap = utils.NewSpiritMap()

type Server struct {
	Handler
}
type Handler func(*Connection)

func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	s := Server{Handler: h}
	s.serveWebSocket(w, req)
}
func (s Server) serveWebSocket(w http.ResponseWriter, r *http.Request) {
	upGrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
		return true
	}}
	var (
		wsConn *websocket.Conn
		conn   *Connection
		err    error
	)
	clientId := r.Header.Get("clientId")
	if clientId == "" {
		return
	}
	uid, _ := uuid.NewV4()
	header := http.Header{
	}
	serverId := uid.String()
	header.Add("serverId", serverId)
	if wsConn, err = upGrader.Upgrade(w, r, header); err != nil {
		return
	}
	if conn, err = InitConnection(wsConn, true, header); err != nil {
		goto ERR
	} else {
		WsMap.Set(serverId, clientId)
		log.Printf("client:[%s] connected successful", clientId)
	}
	s.Handler(conn)
ERR:
	//TODO :关闭连接
	conn.Close()
}
